// CyTargetLinker,
// a Cytoscape plugin to extend biological networks with regulatory interaction
//
// Copyright 2011-2013 Department of Bioinformatics - BiGCaT, Maastricht University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package cytargetlinker.io;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import cytargetlinker.data.Edge;
import cytargetlinker.data.Node;

public class CyTargetLinkerParser extends DefaultHandler {

	private List<Node> nodeList;
	private List<Edge> edgeList;
	
	private Node currentNode = null;
	private Edge currentEdge = null;
	
	private String networkName;
	private Map<String, String> networkProperties;
	private Map<String, Node> nodeIds;
	
	private List<String> ids;
	
	public CyTargetLinkerParser(List<String> ids) {
		this.ids = ids;
		nodeList = new ArrayList<Node>();
		edgeList = new ArrayList<Edge>();
		networkProperties = new HashMap<String, String>();
		nodeIds = new HashMap<String, Node>();
	}
	
	public void clean() {
			nodeList.clear();
			edgeList.clear();
			networkProperties.clear();
			nodeIds.clear();
		}
	
	/**
	 * startElement is called whenever the SAX parser sees a start tag.  We
	 * use this as the way to fire our state table.
	 *
	 * @param namespace the URL of the namespace (full spec)
	 * @param localName the tag itself, stripped of all namespace stuff
	 * @param qName the tag with the namespace prefix
	 * @param atts the Attributes list from the tag
	 */
	public void startElement(String namespace, 
            String localName, 
            String qName,
            Attributes atts) throws SAXException {
		
		if(localName.equals("node")) {
			String id = atts.getValue("id");
			if(id != null && !id.equals("")) {
				currentNode = new Node(id);
				currentNode.addIdentifier(id);
				nodeIds.put(id, currentNode);
			}
		} else if (localName.equals("edge")) {
			String id = atts.getValue("id");
			String source = atts.getValue("source");
			String target = atts.getValue("target");
			
			if(id != null && source != null && target != null) {
				Node sourceNode = nodeIds.get(source);
				Node targetNode = nodeIds.get(target);
				
				if(sourceNode != null && targetNode != null) {
					List<String> list = new ArrayList<String>();
					list.addAll(sourceNode.getIdentifiers());
					list.addAll(targetNode.getIdentifiers());

					for(String str : list) {
						if(ids.contains(str)) {
							currentEdge = new Edge(id);
							currentEdge.setSource(sourceNode);
							currentEdge.setTarget(targetNode);
							break;
						}
					}
					
					
				}
			}
		} else if (localName.equals("att")) {
			parseProperties(atts);
		} else if (localName.equals("graph")) {
			String label = atts.getValue("label");
			if(label != null) {
				networkName = label;
			}
		}
	}
	
	private void parseProperties(Attributes atts) {
		String name = atts.getValue("name");
		String label = atts.getValue("label");
		String value = atts.getValue("value");
			
		String key = "";
			
		if(label != null) {
			key = label;
		} else if (name != null) {
			key = name;
		}
			
		if(key != null && value != null) {
			if(currentNode != null) {
				if(key.equals("identifiers")) {
					currentNode.addIdentifier(value);
				} else {
					currentNode.addProperty(key, value);
				}
			} else if (currentEdge != null) {
				currentEdge.addProperty(key, value);
			} else {
				networkProperties.put(key, value);
			}
		}
	}
	
	/**
	 * endElement is called whenever the SAX parser sees an end tag.  We
	 * use this as the way to fire our state table.
	 *
	 * @param uri the URL of the namespace (full spec)
	 * @param localName the tag itself, stripped of all namespace stuff
	 * @param qName the tag with the namespace prefix
	 */
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if(localName.equals("node")) {
			if(currentNode != null) {
				nodeList.add(currentNode);
				currentNode = null;
			}
		} else if (localName.equals("edge")) {
			if(currentEdge != null) {
				edgeList.add(currentEdge);
				currentEdge = null;
			}
		}
	}
	
	
	public String getNetworkName() {
		return networkName;
	}
	
	public List<Node> getNodeList() {
		return nodeList;
	}
	
	public List<Edge> getEdgeList() {
		return edgeList;
	}

	public Map<String, String> getNetworkProperties() {
		return networkProperties;
	}
}